package common.display
{
    import flash.display.DisplayObject;
    import flash.display.DisplayObjectContainer;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Point;
    import flash.geom.Rectangle;

    [Event(name = "componentResize" , type = "nebula.events.ComponentEvent")]
    [Event(name = "updateLayout" , type = "nebula.events.LayoutEvent")]

    public class AbstractComponent extends Sprite
    {
        public namespace hide;
        hide var isInternalComponent:Boolean;
        protected var _autoLayoutHeightEnabled:Boolean;
        protected var _autoLayoutWidthEnabled:Boolean;
        protected var _drawing:Boolean;
        protected var _isEnabled:Boolean;

        protected var _foreLayer:DisplayObjectContainer;
        protected var _maskLayer:DisplayObjectContainer;
        protected var _substanceLayer:DisplayObjectContainer;
        protected var _height:Number;
        protected var _width:Number;


        private var _drawContinue:Boolean;
        private var _willRedraw:Boolean;
        private var _backgroundLayer:DisplayObjectContainer;

        private var _mask:Shape;
        private var _borderLayer:Sprite;
        private var _rect:Sprite;
        private var _backgroundColor:uint;

        public function AbstractComponent():void
        {
            hide::isInternalComponent = false;
            _drawContinue = false;
            _drawing = false;
            _autoLayoutWidthEnabled = false;
            _autoLayoutHeightEnabled = false;
            _willRedraw = false;
            _isEnabled = true;
            _width = 0;
            _height = 0;
            _backgroundColor = 0;
            _rect = new Sprite ();
            _rect.graphics.beginFill (0 , 0);
            _rect.graphics.drawRect (0 , 0 , 1 , 1);
            _rect.width = 0;
            _rect.height = 0;
            _mask = new Shape ();
            _mask.graphics.beginFill (0 , 0);
            _mask.graphics.drawRect (0 , 0 , 1 , 1);
            _mask.width = 0;
            _mask.height = 0;
            _substanceLayer = new Sprite ();
            _substanceLayer.mouseEnabled = false;
            _borderLayer = new Sprite ();
            _borderLayer.mouseEnabled = false;
            _borderLayer.mouseChildren = false;
            _backgroundLayer = new Sprite ();
            _backgroundLayer.mouseEnabled = false;
            _backgroundLayer.mouseChildren = false;
            _maskLayer = new Sprite ();
            _maskLayer.mouseEnabled = false;
            _foreLayer = new Sprite ();
            _foreLayer.mouseEnabled = false;
            _foreLayer.mouseChildren = false;
            super.addChild (_rect);
            super.addChild (_backgroundLayer);
            super.addChild (_maskLayer);
            super.addChild (_foreLayer);
            super.addChild (_borderLayer);
            _maskLayer.addChild (_mask);
            _maskLayer.addChild (_substanceLayer);

            _maskLayer.mask = _mask;
            this.addEventListener (Event.ADDED_TO_STAGE , _addedToStageHandler , false , 0 , true);
        }

        public function get autoLayoutHeightEnabled():Boolean
        {
            return _autoLayoutHeightEnabled;
        }

        public function set autoLayoutHeightEnabled(value:Boolean):void
        {
            _autoLayoutHeightEnabled = value;
        }

        public function get autoLayoutWidthEnabled():Boolean
        {
            return _autoLayoutWidthEnabled;
        }

        public function set autoLayoutWidthEnabled(value:Boolean):void
        {
            _autoLayoutWidthEnabled = value;
        }



        public function get backgroundColor():uint
        {
            return _backgroundColor;
        }

        public function set backgroundColor(value:uint):void
        {
            _backgroundColor = value;
            _rect.graphics.clear ();
            _rect.graphics.beginFill (_backgroundColor & 0xFFFFFF , (_backgroundColor >> 24 & 0xFF) / 255);
            _rect.graphics.drawRect (0 , 0 , 1 , 1);
        }



        public override function get buttonMode():Boolean
        {
            return _rect.buttonMode;
        }

        public override function set buttonMode(value:Boolean):void
        {
            _rect.buttonMode = value;
        }

        public function get enabled():Boolean
        {
            return _isEnabled;
        }

        public function set enabled(value:Boolean):void
        {
            _isEnabled = value;
        }


        public function get globalPosition():Point
        {
            return this.localToGlobal (new Point (0 , 0));
        }

        public function get globalRectangle():Rectangle
        {
            var p:Point = globalPosition;
            return new Rectangle (p.x , p.y , _width , _height);
        }

        public override function get height():Number
        {
            return _height;
        }

        public override function set height(value:Number):void
        {
            setSize (_width , value);
        }



        public function get maskEnabled():Boolean
        {
            return _maskLayer.mask != null;
        }

        public function set maskEnabled(value:Boolean):void
        {
            _maskLayer.mask = value ? _mask : null;
        }

        public override function set mouseEnabled(enabled:Boolean):void
        {
            super.mouseEnabled = enabled;
            _rect.mouseEnabled = enabled;
            _rect.mouseChildren = enabled;
        }

        public function get mouseHit():Boolean
        {
            return this.stage != null && this.mouseX >= 0 && this.mouseX <= _width && this.mouseY >= 0 && this.mouseY <= _height;
        }

        public function get mouseHitWithSameLayerComponents():Boolean
        {
            if (this.mouseHit)
            {
                var parent:DisplayObjectContainer = this.parent;
                var max:int = parent.numChildren;
                for (var i:int = parent.getChildIndex (this) + 1 ; i < max ; i++)
                {
                    var other:AbstractComponent = parent.getChildAt (i) as AbstractComponent;
                    if (other != null && other.mouseHit)
                        return false;
                }
                return true;
            }
            else
            {
                return false;
            }
        }



        public override function get useHandCursor():Boolean
        {
            return _rect.useHandCursor;
        }

        public override function set useHandCursor(value:Boolean):void
        {
            _rect.useHandCursor = value;
        }

        public override function get width():Number
        {
            return _width;
        }

        public override function set width(value:Number):void
        {
            setSize (value , _height);
        }

        public override function set x(value:Number):void
        {
            setLocation (value , y);
        }

        public override function set y(value:Number):void
        {
            setLocation (x , value);
        }

        public function get willRedraw():Boolean
        {
            return _willRedraw;
        }

        public function autoLayoutSize():void
        {
            if (_autoLayoutWidthEnabled || _autoLayoutHeightEnabled)
                autoSize (_autoLayoutWidthEnabled , _autoLayoutHeightEnabled);
        }

        public function autoLayoutSizeDisabled():void
        {
            this.autoLayoutWidthEnabled = false;
            this.autoLayoutHeightEnabled = false;
        }

        public function autoLayoutSizeEnabled():void
        {
            this.autoLayoutWidthEnabled = true;
            this.autoLayoutHeightEnabled = true;
        }

        public function autoSize(autoWidth:Boolean = true , autoHeight:Boolean = true):void
        {
            this.setSize (autoWidth ? 0 : _width , autoHeight ? 0 : _height);
        }

        public function redraw():void
        {
            if (_willRedraw)
                _renderHandler (null);
        }



        public function setColor(name:String , color:uint):void
        {
        }

        public function setDefaultStyle():void
        {
        }

        public function setLocation(x:int , y:int):void
        {
            super.x = x;
            super.y = y;
        }

        public function setLocationFromGlobal(pos:Point):void
        {
            if (parent != null)
            {
                pos = parent.globalToLocal (pos);
                setLocation (pos.x , pos.y);
            }
        }

        public function setLocationPoint(pos:Point):void
        {
            this.setLocation (pos.x , pos.y);
        }

        public function setSize(width:int , height:int):void
        {
            if (width < 0)
                width = 0;
            if (height < 0)
                height = 0;
            if (_width != width || _height != height)
            {
                _width = width;
                _height = height;
                update ();
//                this.dispatchEvent (new ComponentEvent (ComponentEvent.COMPONENT_RESIZE));
//                this.dispatchEvent (new LayoutEvent (LayoutEvent.UPDATE_LAYOUT));
            }
        }

        public function setSkin(name:String , asset:DisplayObject):void
        {
        }

        public function styleChangedHandler(e:Event):void
        {
        }

        public function update():void
        {
            if (!_willRedraw)
            {
                _willRedraw = true;
                if (this.stage != null && !hide::isInternalComponent)
                    this.addEventListener (Event.RENDER , _renderHandler , false , 0 , true);
//                Nebula.invalidate ();
            }
            else if (_drawing)
            {
                _drawContinue = true;
            }
        }

        protected function _childrenRedraw():void
        {
        }

//        protected function _getAvailableHeight():int
//        {
//            return _height - (_internalBorderSize == null ? 0 : _internalBorderSize.height);
//        }
//
//        protected function _getAvailableWidth():int
//        {
//            return _width - (_internalBorderSize == null ? 0 : _internalBorderSize.width);
//        }

        protected function _redraw():void
        {
            _rect.width = _width;
            _rect.height = _height;
            _mask.width = _width;
            _mask.height = _height;
//            if (_background != null)
//                _background.redraw (_width , _height);
            _setBorder ();
        }

        protected function _setExternalBorderSize():void
        {
//            this.dispatchEvent (new LayoutEvent (LayoutEvent.UPDATE_LAYOUT));
        }

        protected function _setInternalBorderSize():void
        {
        }

        protected function _setStyle():void
        {
        }

        private function _setBorder():void
        {
//            if (_border != null)
//                _border.redraw (_borderLayer , _width , _height);
        }

        //handlers
//        protected function _childrenResizeHandler(e:ComponentEvent):void
//        {
//            update ();
//        }

        private function _addedToStageHandler(e:Event):void
        {
            this.removeEventListener (Event.ADDED_TO_STAGE , _addedToStageHandler);
            this.addEventListener (Event.REMOVED_FROM_STAGE , _removedFromStageHandler , false , 0 , true);
            if (_willRedraw)
            {
                if (!hide::isInternalComponent)
                {
                    this.addEventListener (Event.RENDER , _renderHandler);
                }
            }
        }

//        private function _externalBorderSizeChangedHandler(e:ComponentEvent):void
//        {
//            _setExternalBorderSize ();
//        }
//
//        private function _internalBorderSizeChangedHandler(e:ComponentEvent):void
//        {
//            _setInternalBorderSize ();
//        }

        private function _removedFromStageHandler(e:Event):void
        {
            this.removeEventListener (Event.REMOVED_FROM_STAGE , _removedFromStageHandler);
            this.removeEventListener (Event.RENDER , _renderHandler);
            this.addEventListener (Event.ADDED_TO_STAGE , _addedToStageHandler , false , 0 , true);
        }

        private function _renderHandler(e:Event):void
        {
            _drawing = true;
            _redraw ();
            _childrenRedraw ();
            this.removeEventListener (Event.RENDER , _renderHandler);
            _willRedraw = false;
            _drawing = false;
            if (_drawContinue)
            {
                _drawContinue = false
                update ();
            }
        }

        //hide
        public function get hideNamespace():Namespace
        {
            return hide;
        }

//        hide function set parentLayout(value:AbstractLayout):void
//        {
//            _parentLayout = value;
//        }
    }
}
